#include "qapttest.h"
#include "ui_qapttest.h"

#include <QDebug>
#include <QApplication>
#include <QDir>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QStackedWidget>

#include "commitwidget.h"
#include "cacheupdatewidget.h"

#include <QApt/Backend>
#include <QApt/Transaction>

QAptTest::QAptTest(QWidget *parent) : QMainWindow(parent), ui(new Ui::QAptTest)
{
    ui->setupUi(this);

    m_stack = ui->stack;

    m_mainWidget = ui->mainWidget;

    m_cacheUpdateWidget = new CacheUpdateWidget(m_stack);
    m_stack->addWidget(m_cacheUpdateWidget);
    m_commitWidget = new CommitWidget(m_stack);
    m_stack->addWidget(m_commitWidget);

    m_stack->setCurrentWidget(m_mainWidget);

    m_lineEdit = ui->lineEdit;
    connect(m_lineEdit, SIGNAL(returnPressed()), this, SLOT(updateLabels()));

    QPushButton *showButton = ui->showButton;
    connect(showButton, SIGNAL(clicked()), this, SLOT(updateLabels()));

    m_actionButton = ui->actionButton;
    m_actionButton->setVisible(false);
    connect(m_actionButton, SIGNAL(clicked()), this, SLOT(commitAction()));

    m_nameLabel = ui->nameLabel;
    m_sectionLabel = ui->sectionLabel;
    m_originLabel = ui->originLabel;
    m_installedSizeLabel = ui->installedSizeLabel;
    m_maintainerLabel = ui->maintainerLabel;
    m_sourceLabel = ui->sourceLabel;
    m_versionLabel = ui->versionLabel;
    m_packageSizeLabel = ui->packageSizeLabel;
    m_shortDescriptionLabel = ui->shortDescriptionLabel;
    m_longDescriptionLabel = ui->longDescriptionLabel;

    QPushButton *cacheButton = ui->cacheButton;
    // cacheButton->setIcon(KIcon("view-refresh"));
    connect(cacheButton, SIGNAL(clicked()), this, SLOT(updateCache()));

    QPushButton *upgradeButton = ui->upgradeButton;
    // upgradeButton->setIcon(KIcon("system-software-update"));
    connect(upgradeButton, SIGNAL(clicked()), this, SLOT(upgrade()));

    // Package count labels in the statusbar
    m_packageCountLabel = new QLabel(this);
    m_changedPackagesLabel = new QLabel(this);
    statusBar()->addWidget(m_packageCountLabel);
    statusBar()->addWidget(m_changedPackagesLabel);
    statusBar()->show();

    m_backend = new QApt::Backend(this);
    m_backend->init();
    connect(m_backend, SIGNAL(packageChanged()), this, SLOT(updateStatusBar()));

    updateLabels();
    updateStatusBar();
    setCentralWidget(m_stack);

    // m_debconfGui = new DebconfKde::DebconfGui(QString("/tmp/qapt-sock"));
    // m_debconfGui->connect(m_debconfGui, SIGNAL(activated()), m_debconfGui, SLOT(show()));
    // m_debconfGui->connect(m_debconfGui, SIGNAL(deactivated()), m_debconfGui, SLOT(hide()));

    QString selection_file = QString("%1/%2").arg(qApp->applicationDirPath(), "selection_file.txt");
    qDebug().noquote() << "SelectionFile:" << selection_file;
    m_backend->saveInstalledPackagesList(selection_file);
}

QAptTest::~QAptTest()
{
    delete ui;
}

void QAptTest::changeEvent(QEvent *e)
{
    QMainWindow::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

void QAptTest::updateLabels()
{
    m_package = m_backend->package(m_lineEdit->text());

    if (!m_package) {
        return;
    }

    // Gotta be careful when getting a package directly from the user's input. We can't currently
    // return empty Package containers when the package doesn't exist. And this is why most
    // package managers are MVC based. ;-)
    m_nameLabel->setText(QString("<b>Package:</b> %1").arg(m_package->name()));
    m_sectionLabel->setText(QString("<b>Section:</b> %1").arg(m_package->section()));
    m_originLabel->setText(QString("<b>Origin:</b> %1").arg(m_package->origin()));
    QString installedSize(QString::number(m_package->availableInstalledSize()));
    m_installedSizeLabel->setText(QString("<b>Installed Size:</b> %1").arg(installedSize));
    m_maintainerLabel->setText(QString("<b>Maintainer:</b> %1").arg(m_package->maintainer()));
    m_sourceLabel->setText(QString("<b>Source package:</b> %1").arg(m_package->sourcePackage()));
    m_versionLabel->setText(QString("<b>Version:</b> %1").arg(m_package->version()));
    QString packageSize(QString::number(m_package->downloadSize()));
    m_packageSizeLabel->setText(QString("<b>Download size:</b> %1").arg(packageSize));
    m_shortDescriptionLabel->setText(QString("<b>Description:</b> %1").arg(m_package->shortDescription()));
    m_longDescriptionLabel->setText(m_package->longDescription());

    if (!m_package->isInstalled()) {
        if (m_package->state() & QApt::Package::Upgradeable) {
            m_actionButton->setText("Upgrade Package");
        } else {
            m_actionButton->setText("Install Package");
        }
    } else {
        m_actionButton->setText("Remove Package");
    }
    m_actionButton->setVisible(true);

    qDebug().noquote() << m_package->supportedUntil();
    QApt::PackageList searchList = m_backend->search("kdelibs5");
    foreach (QApt::Package *pkg, searchList) {
        qDebug().noquote() << pkg->name();
    }

    // Uncomment these to see the results in Konsole; I was too lazy to make a GUI for them
    qDebug().noquote() << "============= New package Listing =============";
    QStringList requiredByList(m_package->requiredByList());
    foreach (const QString &name, requiredByList) {
        qDebug().noquote() << "reverse dependency: " << name;
    }

    // A convenient way to check the install status of a package
    // if (m_package->isInstalled()) {
    //     qDebug().noquote() << "Package is installed!!!";
    // }

}

void QAptTest::updateCache()
{
    if (m_trans) // Transaction running, you could queue these though
        return;

    m_trans = m_backend->updateCache();

    // Provide proxy/locale to the transaction
    // if (KProtocolManager::proxyType() == KProtocolManager::ManualProxy) {
    //     m_trans->setProxy(KProtocolManager::proxyFor("http"));
    // }

    m_trans->setLocale(QLatin1String(setlocale(LC_MESSAGES, 0)));

    // Pass the new current transaction on to our child widgets
    m_cacheUpdateWidget->setTransaction(m_trans);
    connect(m_trans, SIGNAL(statusChanged(QApt::TransactionStatus)), this, SLOT(onTransactionStatusChanged(QApt::TransactionStatus)));

    m_trans->run();
}

void QAptTest::upgrade()
{
    if (m_trans) // Transaction running, you could queue these though
        return;

    // m_debconfGui = new DebconfKde::DebconfGui("/tmp/qapt-sock");
    // m_debconfGui->connect(m_debconfGui, SIGNAL(activated()), m_debconfGui, SLOT(show()));
    // m_debconfGui->connect(m_debconfGui, SIGNAL(deactivated()), m_debconfGui, SLOT(hide()));

    m_trans = m_backend->upgradeSystem(QApt::FullUpgrade);

    // Provide proxy/locale to the transaction
    // if (KProtocolManager::proxyType() == KProtocolManager::ManualProxy) {
    //     m_trans->setProxy(KProtocolManager::proxyFor("http"));
    // }

    m_trans->setLocale(QLatin1String(setlocale(LC_MESSAGES, 0)));

    // Pass the new current transaction on to our child widgets
    m_cacheUpdateWidget->setTransaction(m_trans);
    m_commitWidget->setTransaction(m_trans);
    connect(m_trans, SIGNAL(statusChanged(QApt::TransactionStatus)), this, SLOT(onTransactionStatusChanged(QApt::TransactionStatus)));

    m_trans->run();
}

void QAptTest::commitAction()
{
    if (m_trans) // Transaction running, you could queue these though
        return;

    if (!m_package->isInstalled()) {
        m_package->setInstall();
    } else {
        m_package->setRemove();
    }

    if (m_package->state() & QApt::Package::Upgradeable) {
        m_package->setInstall();
    }

    m_trans = m_backend->commitChanges();

    // Provide proxy/locale to the transaction
    // if (KProtocolManager::proxyType() == KProtocolManager::ManualProxy) {
    //     m_trans->setProxy(KProtocolManager::proxyFor("http"));
    // }

    m_trans->setLocale(QLatin1String(setlocale(LC_MESSAGES, 0)));

    // Pass the new current transaction on to our child widgets
    m_cacheUpdateWidget->setTransaction(m_trans);
    m_commitWidget->setTransaction(m_trans);
    connect(m_trans, SIGNAL(statusChanged(QApt::TransactionStatus)), this, SLOT(onTransactionStatusChanged(QApt::TransactionStatus)));

    m_trans->run();
}

void QAptTest::onTransactionStatusChanged(QApt::TransactionStatus status)
{
    switch (status) {
    case QApt::RunningStatus:
        // For roles that start by downloading something, switch to download view
        if (m_trans->role() == (QApt::UpdateCacheRole | QApt::UpgradeSystemRole | QApt::CommitChangesRole | QApt::DownloadArchivesRole | QApt::InstallFileRole)) {
            m_stack->setCurrentWidget(m_cacheUpdateWidget);
        }
        break;
    case QApt::DownloadingStatus:
        m_stack->setCurrentWidget(m_cacheUpdateWidget);
        break;
    case QApt::CommittingStatus:
        m_stack->setCurrentWidget(m_commitWidget);
        break;
    case QApt::FinishedStatus:
        // FIXME: Determine which transactions need to reload cache on completion
        m_backend->reloadCache();
        m_stack->setCurrentWidget(m_mainWidget);
        updateStatusBar();

        // Clean up transaction object
        m_trans->deleteLater();
        m_trans = 0;
        break;
    default:
        break;
    }
}

void QAptTest::updateStatusBar()
{
    int count_installed = m_backend->packageCount(QApt::Package::Installed);
    int count_upgradeable = m_backend->packageCount(QApt::Package::Upgradeable);
    int count_available = m_backend->packageCount();
    QString count_package = QString::asprintf("%d Installed, %d upgradeable, %d available", count_installed, count_upgradeable, count_available);
    qDebug().noquote() << "StatusBar:" << count_package;
    m_packageCountLabel->setText(count_package);

    int count_to_install = m_backend->packageCount(QApt::Package::ToInstall);
    int count_to_upgrade = m_backend->packageCount(QApt::Package::ToUpgrade);
    int count_to_remove = m_backend->packageCount(QApt::Package::ToRemove);
    QString count_changed = QString::asprintf("%d To install, %d to upgrade, %d to remove", count_to_install, count_to_upgrade, count_to_remove);
    qDebug().noquote() << "StatusBar:" << count_changed;
    m_changedPackagesLabel->setText(count_changed);
}
